using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Conversation;
using System.Diagnostics;
using System.Speech;
using System.Speech.Synthesis;
using System.IO;

namespace LyncTalker
{
    public class LyncTalkerApplicationContext : ApplicationContext
    {
        NotifyIcon notifyIcon = new NotifyIcon();
        Configuration configWindow = new Configuration();

        LyncClient lyncClient;

        List<ConversationHandler> conversations = new List<ConversationHandler>();

        SpeechSynthesizer synth = new SpeechSynthesizer();

        private string lastMessage;

        public LyncTalkerApplicationContext()
        {
            SetupUI();
            SetupVoices();

            try
            {
                lyncClient = LyncClient.GetClient();
            }
            catch (LyncClientException ex)
            {
                try
                {
                    if (StartLyncProcess())
                        lyncClient = LyncClient.GetClient();
                }
                catch (Exception)
                {
                    var errorForm = new ErrorForm();
                    errorForm.ShowDialog();
                }
            }

            if (lyncClient != null)
            {
                AddExistingConversations();

                lyncClient.ConversationManager.ConversationAdded += ConversationManager_ConversationAdded;
                lyncClient.ConversationManager.ConversationRemoved += ConversationManager_ConversationRemoved;
            }
            else
            {
                var errorForm = new ErrorForm();
                errorForm.ShowDialog();
            }

            Application.ApplicationExit += Application_ApplicationExit;

            synth.SpeakAsync("Link Talker On Line");
        }

        private void SetupVoices()
        {
            foreach (var voice in synth.GetInstalledVoices())
            {
                configWindow.AddVoice(voice.VoiceInfo.Name);
            }

            if (!String.IsNullOrEmpty(LyncTalker.Properties.Settings.Default.VoiceName))
            {
                synth.SelectVoice(LyncTalker.Properties.Settings.Default.VoiceName);
                configWindow.SetActiveVoice(LyncTalker.Properties.Settings.Default.VoiceName);
            }
            else
                configWindow.SetActiveVoice(synth.Voice.Name);

            configWindow.VoiceChanged += configWindow_VoiceChanged;
        }

        private void SetupUI()
        {
            MenuItem configMenuItem = new MenuItem("Configuration", new EventHandler(ShowConfig));
            MenuItem exitMenuItem = new MenuItem("Exit", new EventHandler(Exit));

            notifyIcon.Icon = LyncTalker.Properties.Resources.AppIcon;
            notifyIcon.DoubleClick += new EventHandler(ShowConfig);
            notifyIcon.ContextMenu = new ContextMenu(new MenuItem[] { configMenuItem, exitMenuItem });
            notifyIcon.Visible = true;
        }

        private bool StartLyncProcess()
        {
            Process lyncClientProcess = null;

            try
            {
                if (File.Exists("C:\\Program Files (x86)\\Microsoft Lync\\communicator.exe"))
                {
                    lyncClientProcess = Process.Start("C:\\Program Files (x86)\\Microsoft Lync\\communicator.exe");
                }
                else if (File.Exists("C:\\Program Files\\Microsoft Lync\\communicator.exe"))
                {
                    lyncClientProcess = Process.Start("C:\\Program Files (x86)\\Microsoft Lync\\communicator.exe");
                }

                if (lyncClientProcess != null)
                {
                    System.Threading.Thread.Sleep(2000);
                    return true;
                }
                return false;
            }
            catch (FileNotFoundException ex)
            {
                return false;
            }
        }

        private void AddExistingConversations()
        {
            if (lyncClient.ConversationManager.Conversations.Count > 0)
            {
                foreach (var conversation in lyncClient.ConversationManager.Conversations)
                {
                    AddConversation(conversation);
                }
            }
        }

        void Application_ApplicationExit(object sender, EventArgs e)
        {
            notifyIcon.Visible = false;
        }

        void configWindow_VoiceChanged(string voiceName)
        {
            var vn = voiceName;

            try
            {
                synth.SelectVoice(voiceName);
                synth.Speak(voiceName + "selected");
            }
            catch (ArgumentException ex)
            {
                synth.Speak(ex.Message);
            }
        }

        void ConversationManager_ConversationRemoved(object sender, ConversationManagerEventArgs e)
        {
            RemoveConversation(e.Conversation);
        }

        void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
        {
            AddConversation(e.Conversation);
        }

        void AddConversation(Conversation conversation)
        {
            var conversationHandler = new ConversationHandler(conversation);
            conversationHandler.MessageError += new MessageError(conversationService_MessageError);
            conversationHandler.MessageRecived += new MessageReceived(conversationService_MessageRecived);
            conversations.Add(conversationHandler);
            //starts listening to Lync events
            conversationHandler.Start();
        }

        void RemoveConversation(Conversation conversation)
        {
            var toRemove = conversations.Find(c => c.Conversation == conversation);
            if (toRemove != null)
                conversations.Remove(toRemove);
        }

        void ShowConfig(object sender, EventArgs e)
        {
            if (configWindow.Visible)
                configWindow.Focus();
            else
                configWindow.ShowDialog();
        }

        void Exit(object sender, EventArgs e)
        {
            notifyIcon.Visible = false;
            Application.Exit();
        }

        #region Conversation Service event handling (Lync-related events)

        /// <summary>
        /// Called when a message is received for the specified participant.
        /// </summary>
        private void conversationService_MessageRecived(string message, string participantName)
        {
            string firstName = participantName.Split(' ')[0];
            string lastName = participantName.Split(' ')[1];

            StringBuilder messageBuilder = new StringBuilder();
            //For some reason, this event gets called twice causing each message to be read twice
            if (message != lastMessage)
            {
                if (configWindow.SpeakFirstName)
                    messageBuilder.Append(firstName + " ");

                if (configWindow.SpeakLastName)
                    messageBuilder.Append(lastName + " ");

                if ((configWindow.SpeakFirstName) || (configWindow.SpeakLastName))
                    messageBuilder.Append("says, ");

                messageBuilder.Append(message);

                synth.SpeakAsync(messageBuilder.ToString());

                Debug.WriteLine(message);
            }
            lastMessage = message;
        }

        private void conversationService_MessageError(Exception ex)
        {
            synth.Speak("Error, " + ex.Message);
        }

        #endregion
    }
}
